package xyz.fefine;

import java.util.List;
import java.util.Objects;

/**
 * Created by feng_ on 2016/9/2.
 * 表达式
 * 含有 { 赋值 ， 简单数字计算 ， 字符串拼接 ， 比较}
 * 必须返回数值
 */
public class BinaryExpr extends ASTList {
    public BinaryExpr(List<ASTree> list) {
        super(list);
    }

    @Override
    public void lookup(Symbols syms) {

        ASTree left = left();
        if ("=".equals(operator())) {
            if (left instanceof Name) {
                ((Name) left).lookupForAssign(syms);
                right().lookup(syms);
                return;
            }
        }
        left.lookup(syms);
        right().lookup(syms);
    }



    @Override
    public Object eval(Enviorment enviorment) {
//        Object left = left().eval(enviorment);

        String opera = operator();
        if (opera.equals("=")) {
            //赋值
            if (left() instanceof Name) {
                //
                Object right = right().eval(enviorment);
                //name中还有存储位置,因此把赋值操作转移到name中
                ((Name) left()).evalForAssign(enviorment,right);
//                enviorment.put(((Name) left()).name(), right);
                return right;
            }else if (left() instanceof PrimaryExpr) {      //computeAssign function
                PrimaryExpr pe = (PrimaryExpr) left();
                Object rValue = right().eval(enviorment);
                //0 is name  1 is arrayref
                //采用递归实现,仿照函数的实现
                //获取数组
                Object[] arr = (Object[])(pe.child(0).eval(enviorment));
                int i = 1;
                for (;pe.numChildren() > i + 1;i++) {
                    //获取索引
                    Object index = ((ArrayRef)pe.postfix(i)).index().eval(enviorment);
                    if (index instanceof Integer) {
                        arr = (Object[]) arr[(Integer) index];
                    }else {
                        throw new StoneException("bad index value ", this);
                    }
                }
                //最后一个索引
                Object index = ((ArrayRef)pe.child(i)).index().eval(enviorment);
                if (index instanceof Integer) {
                    arr[(Integer) index] = rValue;
                }else {
                    throw new StoneException("bad index value ", this);
                }
                return rValue;

            } else {
                throw new StoneException("bad assignment ", this);
            }
        } else {
            Object le = left().eval(enviorment);
            Object ri = right().eval(enviorment);
            if (le instanceof Integer && ri instanceof Integer){
                return numberOperate((Integer)le, operator(), (Integer) ri);
            }else{
                return objectOperate(le, operator(), ri);
            }
        }

//        return super.eval(enviorment);
    }

    private Object objectOperate(Object l, String op, Object r) {
        if (op.equals("+")) {
            return new String(l.toString() + r.toString());
        } else if (op.equals("==")) {
            if (l == null) {
                return r == null ? TRUE : FALSE;
            }
            return l.equals(r) ? TRUE : FALSE;
        } else {
            throw new StoneException("bad operator " + op, this);
        }
    }

    /**
     * 对数字进行 + - * / 。。。
     * @param l
     * @param op
     * @param r
     * @return
     */
    private Object numberOperate(Integer l, String op, Integer r) {
        int a = l.intValue();
        int b = r.intValue();
        switch (op) {
            case "+" :
                return new Integer(a + b);
            case "-" :
                return new Integer(a - b);
            case "*" :
                return new Integer(a * b);
            case "/" :
                return new Integer(a / b);
            case "%" :
                return new Integer(a % b);
            case ">" :
                return a > b ? TRUE : FALSE;
            case "<" :
                return a < b ? TRUE : FALSE;
            case ">=" :
                return a >= b ? TRUE : FALSE;
            case "<=" :
                return a <= b ? TRUE : FALSE;
            case "==" :
                return a == b ? TRUE : FALSE;
            default:
                throw new StoneException("bad operator " + op, this);

        }

    }

    public ASTree left(){
        return child(0);
    }
    public String operator(){
        return ((ASTLeaf)child(1)).token().getString();
    }
    public ASTree right(){
        return child(2);
    }
}
